#pragma once

#include <functional>

template<class T>
class MyList
{
	using DataDeallocator = void (*)(T*);
public:
	struct ListNode
	{
		int UID = 0;
		T* data = nullptr;
		ListNode* next = nullptr, * prev = nullptr;
	};

public:
	MyList() {};
	MyList(DataDeallocator deallocator)
	{
		deallocate = deallocator;
	};
	~MyList()
	{
		destory();
	};

	// just do something esay with the items.
	void for_each(void(*func)(T*));
	// do more advanced thing with the items.
	void for_each_cpp11(std::function<void(T*, ListNode*)> func);

	
	// unsafe but I'm not sure whether I could use smart pointers.
	auto search(bool(*conform)(T*, void*), void* userData);
	auto find(int UID);
	// add the node pointer which satisfied the 'conform' func into a new sub list.
	auto fuzzy_search(bool(*conform)(T*, void*), void* userData);
	// funtion cmp: Checks whether the data should follow the list_data. If so, resturn true.
	bool insert(T* data, bool(*cmp)(T* list_data, T* data), bool(*check)(T* list_data, T* data));

	void remove(int UID);
	void remove(ListNode* node_ptr);
	void remove_when(bool(*func)(T* data, void* userData), void* userData);

	auto filter_collect(bool(*filter)(T&, void*), void* userData, bool(*cmp)(T*, T*));
	
	void push_back_p(T* data);
	void push_back(T data);

	void destory();

	size_t size();
private:
	void push_back(T data, int UID);
	bool insert(T* data, int UID, bool(*cmp)(T* list_data, T* data), bool(*check)(T* list_data, T* data));

	ListNode* head = nullptr;
	ListNode* tail = nullptr;
	DataDeallocator deallocate = nullptr;
	int cntUID = 0;
};

#include "MyList.inl"